classdef Filter < Signal

properties 
	LoopOrder;
	Bandwidth;
	DetectorGain;
	IntegrationTime;
end % end of properties

properties (SetAccess = protected)
	Coefficients;
	States;
	filter;
end % end of properties

properties (SetAccess = protected, GetAccess = protected)
	filter1;
	filter2;
	filter3;
end % end of properties

methods

	function obj = Filter(Name, ...
 												LoopOrder, Bandwidth, DetectorGain, IntegrationTime)
		obj = obj@Signal(Name);
		obj.LoopOrder = LoopOrder;
		obj.Bandwidth = Bandwidth;
		obj.DetectorGain = DetectorGain;
		obj.IntegrationTime = IntegrationTime;
		obj.reset();
	end

	function obj = refresh(obj)
		obj.Coefficients = Filter.getCoefficients(obj.LoopOrder, obj.Bandwidth,...
																							obj.DetectorGain, ...
																						 	obj.IntegrationTime);
		n_new = obj.LoopOrder-1;
		if (isempty(obj.States))
			obj.States = zeros(1, n_new);
		else
			[m n] = size(obj.States);
			if (n_new > 0) 
				tmp = obj.States;
				obj.States = zeros(1, n_new);
				if (n_new > n)
					obj.States(1, 1:n) = tmp; 
				elseif (n_new < n)
					obj.States = tmp(1, 1:n_new); 
				else
					obj.States = tmp;
				end	
			else
				obj.States = [];
			end
		end
		
	end

	function obj = reset(obj)
		obj.Coefficients = Filter.getCoefficients(obj.LoopOrder, obj.Bandwidth,...
																							obj.DetectorGain, ...
																						 	obj.IntegrationTime);
		n_new = obj.LoopOrder-1;
		obj.States = zeros(1, n_new);
	end

	function obj = set.LoopOrder(obj, val)
		obj.LoopOrder = val;
		switch (obj.LoopOrder)
			case 1
				obj.filter = @obj.filter1;
			case 2 
				obj.filter = @obj.filter2;
			case 3 
				obj.filter = @obj.filter3;
			otherwise
				error('Unknown loop order')
		end
	end

end

methods (Static)

	function out = getCoefficients(LoopOrder, Bandwidth, DetectorGain,...
																 IntegrationTime)
		Bn = Bandwidth;
		Kmu = DetectorGain;
		T = IntegrationTime;
		switch LoopOrder
			case 1
				Kf = 4*Bn*T/Kmu;
				out(1) = Kf; 
			case 2
				zeta = 0.707;
				OmegaN = 2*Bn*T/zeta* 1/(1+1/(4*zeta)); 
				a1 = OmegaN/(zeta*2);
				Kf = 2*OmegaN*zeta/Kmu;
				out(1) = Kf;
				out(2) = a1; 
			case 3
				OmegaN = Bn/0.7845 * T;
				Kf = 2.3 * OmegaN / Kmu;
				a1 = 0.5 * OmegaN;
				a2 = 0.9 * OmegaN;
				out(1) = Kf;
				out(2) = a1; 
				out(3) = a2; 
			otherwise
				error('1. argument LoopOrder must be in {1, 2, 3}');
		end
	end

end % end of methods

end % end of class
